#include <jni.h>
#include <string>
#include <cstdlib>

extern "C"
JNIEXPORT jstring JNICALL


/**
 * 有问题
 * @param env
 * @param instance
 * @return
 */
Java_com_example_myndklearn_MainNative_stringFromJNI(
        JNIEnv *env,
        jobject instance) {
    std::string hello = "Hello from C++阿萨德1";

    jclass clazz = env->GetObjectClass(instance);
    jfieldID keyId = env->GetFieldID(clazz, "key", "Ljava/lang/String;"); // 这个;符号很重要

    if (keyId != NULL) {
        jstring hello2 = static_cast<jstring>(env->GetObjectField(instance, keyId));


        char *newHello = const_cast<char *>(env->GetStringUTFChars(hello2, NULL));
        strcat(const_cast<char *>(hello.c_str()), newHello);
//        strcpy(const_cast<char *>(hello.c_str()), newHello);

        return env->NewStringUTF(newHello);
    } else {
        return env->NewStringUTF(hello.c_str());
    }

}







extern "C"
JNIEXPORT jboolean JNICALL
Java_com_example_myndklearn_MainNative_handleBooleanFromJNI(
        JNIEnv *env,
        jobject /* this */) {

    return static_cast<jboolean>(true);
}


// jni 访问Java的静态变量

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myndklearn_MainNative_chaneStaticIntValue(JNIEnv *env, jobject instance) {

    jclass clazz = env->GetObjectClass(instance);
    jfieldID keyValueId = env->GetStaticFieldID(clazz, "keyValue", "I");
    jint valueInt = env->GetStaticIntField(clazz, keyValueId);
    valueInt++;
    env->SetStaticIntField(clazz, keyValueId, valueInt);
}

// jni 访问Java的void 带一个Int 参数的method`
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myndklearn_MainNative_assessMethod(JNIEnv *env, jobject instance) {

    jclass clazz = env->GetObjectClass(instance);
    jmethodID methodID = env->GetMethodID(clazz, "handleKeyValue", "(I)V");
    env->CallVoidMethod(instance, methodID, 200);
}


/**
 * 访问父类的方法
 */
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myndklearn_MainNative_callHumanSyaHi(JNIEnv *env, jobject instance) {
    jclass clazz = env->GetObjectClass(instance);
    // 获取Man属性 对象
    jfieldID fieldID = env->GetFieldID(clazz, "human", "Lcom/example/myndklearn/Human;");
    jobject humanObj = env->GetObjectField(instance, fieldID);
    // 注意写法和上面获取变量不一致
    // 写的是父类类名
    jclass humanClass = env->FindClass("com/example/myndklearn/Human");
    jmethodID syaHiMethodId = env->GetMethodID(humanClass, "sayHi", "()V");
    env->CallNonvirtualVoidMethod(humanObj, humanClass, syaHiMethodId);
    env->CallVoidMethod(humanObj, syaHiMethodId);

}
/**
 * 访问构造方法
 */

extern "C"
JNIEXPORT jobject JNICALL
Java_com_example_myndklearn_MainNative_accessConstructor(JNIEnv *env, jobject instance) {

    jclass cls = env->FindClass("java/util/Date");
    //jmethodID
    jmethodID constructor_mid = env->GetMethodID(cls, "<init>", "()V");
    //实例化一个Date对象
    jobject date_obj = env->NewObject(cls, constructor_mid);
    //调用getTime方法
    jmethodID mid = env->GetMethodID(cls, "getTime", "()J");
    jlong time = env->CallLongMethod(date_obj, mid);

    // 在Android上是看不到的
    printf("\ntime:%lld==========================================\n", time);

    return date_obj;
}


int compare(const void *pFirst, const void *pSecond) {
    return *(int *) pFirst - *(int *) pSecond;  //升序排序

    //return *(int *)b - *(int *)a; //降序排序
    //return *(double *)a > *(double *)b ? 1 : -1;
    //返回值的问题，显然cmp返回的是一个整型，所以避免double返回小数而被丢失，用一个判断返回值。
}

extern "C"
JNIEXPORT void JNICALL
/**
 * 处理数组排序
 * @param env
 * @param instance
 * @param intArray
 * @return
 */
Java_com_example_myndklearn_MainNative_handleArray(JNIEnv *env, jobject instance, jintArray intArray) {
    jint *pIntArray = env->GetIntArrayElements(intArray, nullptr); // JNI_FALSE 可以修改数组
    int len = env->GetArrayLength(intArray);
    qsort(pIntArray, static_cast<size_t>(len), sizeof(jint), compare);
    // 同步 将C++ 操作的内存同步到Java中
    // mode 0 , Java 数组进行更新，并且释放C/C++数组
    // JNI_ABORT, Java数组不进行更新，但是释放C/C++数组
    // JNI_COMMIT,Java数组进行更新,不释放C/C++数组，但是函数执行完了之后还是会释放
    env->ReleaseIntArrayElements(intArray, pIntArray, 0);
}

extern "C"
JNIEXPORT jintArray JNICALL
/**
 * 返回数组
 * @param env
 * @param instance
 * @param intArray
 */
Java_com_example_myndklearn_MainNative_getIntArray(JNIEnv *env, jobject instance, jint len) {
    jintArray intArray = env->NewIntArray(len);
    jint *pIntArray = env->GetIntArrayElements(intArray, nullptr);
    for (int i = 0; i < len; ++i) {
        pIntArray[i] = i;
    }

    env->ReleaseIntArrayElements(intArray, pIntArray, 0);

    return intArray;
}


// 全局引用
// 共享(跨多个线程)，手动释放
jstring global_string;
jstring globalWeakString;

extern "C"
JNIEXPORT void JNICALL
/**
 * 创建全局的变量
 * @param env
 * @param instance
 */
Java_com_example_myndklearn_MainNative_createGlobalString(JNIEnv *env, jobject instance) {

    global_string = static_cast<jstring>(env->NewGlobalRef((env->NewStringUTF("jni devep is  powerful！"))));

}

extern "C"
JNIEXPORT jstring JNICALL
/**
 * 获取全局变量
 * @param env
 * @param instance
 * @return
 */
Java_com_example_myndklearn_MainNative_getGlobalString(JNIEnv *env, jobject instance) {
    return global_string;
}
extern "C"
JNIEXPORT void JNICALL

/**
 * 释放全局变量
 * @param env
 * @param instance
 */
Java_com_example_myndklearn_MainNative_deleteGlobalString(JNIEnv *env, jobject instance) {
    env->DeleteGlobalRef(global_string);
}




extern "C"
JNIEXPORT void JNICALL
/**
 * 弱全局引用
 * @param env
 * @param instance
 */
Java_com_example_myndklearn_MainNative_createWeakGlobalString(JNIEnv *env, jobject instance) {
    globalWeakString = static_cast<jstring>(env->NewWeakGlobalRef((env->NewStringUTF("jni devep is  weak！"))));
}


char password[] = "zzyy";

extern "C"
JNIEXPORT jstring JNICALL
/**
 * 文件加密
 * @param env
 * @param instance
 * @param normalFilePath_  需要加密的文件路径
 * @return
 */
Java_com_example_myndklearn_MainNative_cryptFile(JNIEnv *env, jobject instance, jstring normalFilePath_,
                                                 jstring cryptFilePath_) {

    const char *cryptFilePath = env->GetStringUTFChars(cryptFilePath_, nullptr);
    const char *normalFilePath = env->GetStringUTFChars(normalFilePath_, nullptr);


    FILE *pNormalFile = fopen(normalFilePath, "rbe");
    FILE *pCryptFile = fopen(cryptFilePath, "wbe");

    int ch;
    int index = 0;
    int passwordLen = strlen(password);
    while ((ch = fgetc(pNormalFile)) != EOF) {
        fputc(ch ^ password[index % passwordLen], pCryptFile);
        index++;
    }

    fclose(pNormalFile);
    fclose(pCryptFile);

    env->ReleaseStringUTFChars(cryptFilePath_, cryptFilePath);
    env->ReleaseStringUTFChars(normalFilePath_, normalFilePath);


    return cryptFilePath_;
}




extern "C"
JNIEXPORT jstring JNICALL

/**
 * 文件解密
 * @param env
 * @param instance
 * @param cryptFilePath_
 * @param decryptFilePath_
 * @return
 */
Java_com_example_myndklearn_MainNative_decryptFile(JNIEnv *env, jobject instance, jstring cryptFilePath_,
                                                   jstring decryptFilePath_) {
    const char *cryptFilePath = env->GetStringUTFChars(cryptFilePath_, nullptr);
    const char *decryptFilePath = env->GetStringUTFChars(decryptFilePath_, nullptr);

    FILE *pNormalFile = fopen(cryptFilePath, "rbe");
    FILE *pDecryptFile = fopen(decryptFilePath, "wbe");

    int ch;
    int index = 0;
    int passwordLen = strlen(password);
    while ((ch = fgetc(pNormalFile)) != EOF) {
        fputc(ch ^ password[index % passwordLen], pDecryptFile);
        index++;
    }

    fclose(pNormalFile);
    fclose(pDecryptFile);


    env->ReleaseStringUTFChars(cryptFilePath_, cryptFilePath);
    env->ReleaseStringUTFChars(decryptFilePath_, decryptFilePath);


    return decryptFilePath_;
}



